package com.visec.hdy.transmission.rmi.code;

import java.io.IOException;
import java.net.Socket;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Set;
import java.util.Timer;

import com.visec.hdy.transmission.rmi.config.RMIModel;
import com.visec.hdy.transmission.rmi.unicast.UnicastManager;
import com.visec.hdy.transmission.rmi.unicast.UnicastManagerImp;

public class RMIServerImp implements RMIServer {

	private Registry registry;

	private RMIModel rmiModel;

	private UnicastManager unicastManager;

	private Timer notify;

	protected RMIServerImp() {
		this.unicastManager = new UnicastManagerImp();
	}

	public static RMIClient instanceClient(RMIModel m) {
		RMIServerImp r = new RMIServerImp();
		try {
			r.registry = LocateRegistry.getRegistry(m.getIp(), m.getPort());
			r.rmiModel = m;
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return r;
	}

	public static RMIServer instanceServer(RMIModel m) {
		RMIServerImp r = new RMIServerImp();
		try {
			r.registry = LocateRegistry.createRegistry(m.getPort());
			r.rmiModel = m;
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return r;
	}

	public Remote lookup() {
		return lookup(this.rmiModel.getRmiUrl());
	}

	public Remote lookup(String url) {
		try {
			return registry.lookup(url);
		} catch (AccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			this.unicastManager.unexportObject(url, false);
			return null;
		}
		return null;
	}

	protected int testConnect() {
		try (Socket s = new Socket(rmiModel.getIp(), rmiModel.getPort())) {
			return 1;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			return 0;
		}
	}

	public void bind(String url, Remote target) {
		try {
			unicastManager.exportObject(url, target, rmiModel.getExportPort());
			registry.rebind(url, target);
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void bindInNull(String url, Remote target) {
		while (lookup(url) != null) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.unicastManager.unexportObject(url, false);
		bind(url, target);
	}

	public void bind(Remote target) {
		bind(rmiModel.getRmiUrl(), target);
	}

	public void unbind() {
		unbind(this.rmiModel.getRmiUrl());
	}

	@Override
	public void unbind(String url) {
		// TODO Auto-generated method stub
		try {
			registry.unbind(url);
			this.unicastManager.unexportObject(url, false);
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NotBoundException e) {
			// TODO Auto-generated catch block
			return;
		}
	}

	@Override
	public void setNotify(RMINotify r) {
		// TODO Auto-generated method stub
		clearNotify();
		if (rmiModel.getRmiUrl() == null)
			try {
				throw new Exception("setNotify must has rmiUrl!");
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		notify = new Timer(true);
		notify.scheduleAtFixedRate(new NotifyTask(this, r), 0, 100);
	}

	@Override
	public void clearNotify() {
		// TODO Auto-generated method stub
		if (notify != null)
			notify.cancel();
	}

	@Override
	public void clearUnicast() {
		// TODO Auto-generated method stub
		Set<String> exportSet = this.unicastManager.exportSet();
		for (String s : exportSet) {
			this.unicastManager.unexportObject(s, true);
		}
	}

	@Override
	public void unicastInNull(String url) {
		// TODO Auto-generated method stub
		while (lookup(url) != null) {
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		this.unicastManager.unexportObject(url, false);
	}

}
